home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
PC World Komputer 2010 April
/
PCWorld0410.iso
/
pluginy Firefox
/
13316
/
13316.xpi
/
content
/
historyViewer.js
< prev
next >
Wrap
Text File
|
2009-10-01
|
46KB
|
1,333 lines
/* Copyright (C) 2009 Norman Solomon
* e-mail: historytree.addon@yahoo.com
*
* The contents of this file are subject to the Mozilla Public License Version
* 1.1 (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at http://www.mozilla.org/MPL/
*
* Software distributed under the License is distributed on an "AS IS" basis,
* WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
* for the specific language governing rights and limitations under the License.
*/
// ***********************************************************************************
// ***** *****
// ***** HISTORY TREE WINDOW TOP-LEVEL JAVASCRIPT FOR "historyViewer.xul" *****
// ***** ------------------------------------------------------------------- *****
// ***** 1) Initializes all constants and globals used by all <script> files *****
// ***** 2) Handles onLoad() and onFocus() which refreshes key arrays etc. *****
// ***** 3) Handles GUI events for all <..> objects in "historyViewer.xul" *****
// ***** 4) Contains shared JS functions used by other <script> JS files *****
// ***** *****
// ***********************************************************************************
// All globals used by "historyViewer.xul" <script...>'s are declared below.
// One global and its associated class are declared in "firefoxOverlay.js"
// No other globals are declared anywhere else in the HistoryTree extension
const CANVAS_MIN_WID = screen.availWidth - 26; // - 26 to enforce vert scrollbar
const CANVAS_MIN_HGT = screen.availHeight - 80; // Allows for top panel height
const CANVAS_BAK_COL = "rgb(38,38,38)"; // Dark grey gCanvas backcolor
const CURR_TAB_COL = "rgb(255,204,170)"; // Orange - Current Tab
const OPEN_TAB_COL = "rgb(255,255,180)"; // Yellow - Open Tab
const CLOSED_TAB_COL = "rgb(180,190,220)"; // Blue - Closed Tab
const WH_RATIO = 0.65; // w/h ratio for all drawm ".jpeg" images
const GRID_VIEW = 1; // Set after <image...> click that shows GridView
const TREE_VIEW = 2; // Set after <image...> click that shows TreeView
const GV_HGAP = 23; // Horizontal gap between drawn GridView images
const GV_VGAP = 52; // Vertical gap between drawn GridView images
// ------------------------------------------------------------------------------
// TreeView constants
const BOX_WIDTH = 142; // Width of TreeView drawn boxes
const BOX_HEIGHT = 65; // Height of TreeView drawn boxes
const BOX_BTN_WID = 21; // Width of buttons below drawn boxes
const BOX_BTN_HGT = 16; // Height of buttons below drawn boxes
const LEVEL_SPACE = (BOX_WIDTH * 0.63) * (-1); // Used in attachParent()
const NODE_BORDER = 41; // *** CRITICAL VALUE - Determines overall tree-size
const BORDER_STEP = 3; // <scale...> change multiplier (changes tree-size)
const MAX_IMG_WID = 750; // Maximum size of expanded TV node image
// TreeView mouse event button click constants
const BTN_NONE = 0; // User clicked on empty TreeView gCanvas area
const BTN_CHANGE_TREE = 1; // User clicked on expand/shrink sub-tree button
const BTN_SHOW_IMAGE = 2; // User clicked on "?" show expanded image button
const BTN_OPEN_PAGE = 3; // User clicked on node to open history page in FF
// --------------------------------------------------------------------------
// Globals passed from "firefoxOverlay.js" via Application storage
var gNodeList; // HistoryNode array in "firefoxOverlay.js"
var gOpenTabIDs; // Array of TabID's that are currently open in FF
var gParamArray; // Various parameters in a App storage array
var gCurrentTabID; // TabID of currently open Tab in FF
var gNodeListLoadLen; // Used in onFocus() to check for FF history changes
// --------------------------------------------------------------------------
// Globals used by both TreeView and GridView
var gParentFFWin; // FF window for which history is shown
var gCanvas; // SVG style Canvas which covers 90% of the window
var gCtx; // gCanvas '2d' context for all drawing
var gCanvasScroller; // gCanvas scroller and mouse-click detect object
var gCurrentView; // Set = TREE_VIEW or GRID_VIEW (see constants above)
var gSearchIndexes; // Array to enable consistant Find Next/Prev search
var gSearchNdx; // Current gSearchIndexes[ndx] for Find Next/Prev
var gGVdispArray; // Array holding images drawn via gGVdispInterval
// Interval timing and function exit flags
var gTabLoadInterval; // Used to clear setInterval()'s and exit GUI functions
var gGVdispInterval; // Used to clear GV setInterval() and exit GUI functions
var gImgExpandInterval; // Used to clear setInterval()'s and exit GUI functions
var gTimeoutInterval; // Used to clear setTimeout()'s and exit GUI functions
var gExitWinFocusEvent; // Exits from unwanted firing of window onFocus() event
// --------------------------------------------------------------------------
// TreeView globals
var gTabRoots; // Array that stores Tab sub-tree Root TreeNode's
var gTreeNodes; // Array that stores ALL TreeNode objects (main array)
var gTreeMinY; // Only used by "treeArranger.js" plantTree()
var gSubTreeSize; // Only used by "treeArranger.js" walkSubTree()
// TreeView image expansion globals
var gExpandedNode; // TreeNode that has an expanded image/info box
var gImgXY; // Expanded image/info box top-left (x,y) on gCanvas
var gInfoBoxWH; // Expanded image/info box (w,h) on gCanvas
var gNodeImageWid; // Used to expand and then clear expanded image
// ***********************************************************
// ***** *****
// ***** WINDOW onLoad() AND onFocus() FUNCTIONALITY *****
// ***** *****
// ***********************************************************
// ========================================================
// Window onLoad event listener, and associated function
// ========================================================
window.addEventListener("load", onLoad, false);
function onLoad()
{
try
{
// Maximise this window, but leave room for user to resize it
// (takes account of current screen resolution)
this.resizeTo(screen.availWidth, screen.availHeight);
gExitWinFocusEvent = true; // Used in onFocus() event
// Set global FF parent window
gParentFFWin = window.opener;
// Initialize gCanvas, making sure it fills the window
gCanvas = document.getElementById('myCanvas');
gCanvas.width = CANVAS_MIN_WID;
gCanvas.height = CANVAS_MIN_HGT;
// Fill gCanvas with dark grey blank rectangle
gCtx = gCanvas.getContext('2d');
gCtx.fillStyle = CANVAS_BAK_COL; // Dark grey
gCtx.fillRect(0, 0, gCanvas.width, gCanvas.height);
// Initialize canvas scroller
var canvasBox = document.getElementById('canvasBox');
gCanvasScroller = canvasBox.boxObject.QueryInterface
(Components.interfaces.nsIScrollBoxObject);
// Init key global vars and display history GV or TV
updateHistoryWhenAllTabsLoaded();
gExitWinFocusEvent = true;
this.focus();
}
catch (e)
{
alert("History Tree Extension - Main Window onLoad() Error");
}
}
// ============================================================
// Extension window onFocus listener and associated function
// ============================================================
window.addEventListener("focus", onFocus, false);
function onFocus()
{
// Update history if global exit flag not set
if (gExitWinFocusEvent)
{
gExitWinFocusEvent = false;
}
else if (gTabLoadInterval === null)
{
// Data update setInterval() is NOT running
if (firefoxHistoryChanged())
{
// FF history has changed so update gTreeNodes[] etc
updateHistoryWhenAllTabsLoaded();
}
else
{
// No additions or deletions to FF history were made, but
// user may have navigated to, or re-loaded, some pages
gParentFFWin.historyTree.putWinParamsArrayInAppStorage();
gParamArray = Application.storage.get("paramArray", null);
gCurrentTabID = gParamArray[0]; // tabID of FF visible Tab
// Set "Window x of y" label
setLabelText_WindowXofY();
// Reset search <textbox...> backgroundColor
var chkSearchURL = document.getElementById("chkSearchURL");
setSearchTextBoxColor(chkSearchURL.checked);
// Update <listbox...> descriptions and text colors
updateListboxTabRootDescriptions();
// Redraw view, so that changed gNodeList[] data appears
if (gCurrentView === TREE_VIEW)
{
drawTree(false, null, null);
}
else
{
var sldDraw = document.getElementById("sldDraw");
var numAcross = (sldDraw.max - sldDraw.value) + 3;
drawAllImagesOnCanvas(numAcross, false);
}
}
}
}
// ====================================================================
// Returns true if FF history has changed since this window lost focus
// ====================================================================
function firefoxHistoryChanged()
{
if (gNodeListLoadLen === null
|| gNodeListLoadLen !== gParentFFWin.historyTree.cNodeList.length
|| !gParentFFWin.historyTree.allTabsLoaded())
{
// Pages were added, or are being added, to FF history
return true;
}
else if (gParentFFWin.historyTree.recentFFhistoryCleared())
{
// "Tools > Clear Recent History" or similar occured
return true;
}
else
{
// Check if FF has same number of Tabs as when window lost focus
var openTabIDs = gParentFFWin.historyTree.openTabIDsList();
if (openTabIDs.length !== gOpenTabIDs.length)
{
// Tabs were opened or closed in FF
return true;
}
else
{
// Check if FF TabID list has changed
for (i = 0; i < openTabIDs.length; i++)
{
if (openTabIDs[i] !== gOpenTabIDs[i])
{
// Tab list or Tab order has changed in FF
return true;
}
}
}
}
// No pages were added to, or removed from, FF history
return false;
}
// ====================================================================
// Updates and shows history when all FF window/page data has loaded
// Called from onLoad(), onFocus() and Next/Prev window button clicks
// ====================================================================
function updateHistoryWhenAllTabsLoaded()
{
// Show "Loading..." message while FF loads window/pages
var loadMsg = "";
if (gParentFFWin.historyTree.cExtLoadProcess)
loadMsg = "Loading Firefox window history...";
else if (!gParentFFWin.historyTree.allTabsLoaded())
loadMsg = "Loading Firefox page data...";
else
loadMsg = "Updating history tree...";
// Show "Loading..." message at top-centre of gCanvas
showBigMessageOnEmptyCanvas(loadMsg, "bold 14pt verdana");
// Disable "historyViewer.xul" top-panel GUI controls
disableOrEnableGUIcontrols(true);
// Start setInterval() that loads and shows history
// (delay is ALWAYS needed to stop slow, "jerky", load)
gTabLoadInterval = setInterval(loadAndShowHistory, 100);
}
// ===========================================================
// Loads App Storage data for FF parent window gParentFFWin,
// then uses this to init key global vars and show history
// ===========================================================
function loadAndShowHistory()
{
// Check if all FF parent window Tabs have fully loaded
if (!gParentFFWin.historyTree.allTabsLoaded()
|| gParentFFWin.historyTree.cExtLoadProcess)
{
// Some FF parent window Tab content is still loading
return;
}
else
{
// All Tabs loaded, so stop setInterval() (flag reset below)
clearInterval(gTabLoadInterval);
}
// ------------------------------------------------
// Clear any running timeouts/intervals
clearInterval(gGVdispInterval);
gGVdispInterval = null;
clearInterval(gImgExpandInterval);
gImgExpandInterval = null;
clearTimeout(gTimeoutInterval);
gTimeoutInterval = null;
// Set "Window x of y" label
setLabelText_WindowXofY();
// ------------------------------------------------
// Call "firefoxOverlay.js" method that puts data in App storage
gParentFFWin.historyTree.putHistoryDataInAppStorage();
// Set globals using retrieved App storage data
gNodeList = Application.storage.get("nodeArray", null);
gOpenTabIDs = Application.storage.get("tabIDarray", null);
gParamArray = Application.storage.get("paramArray", null);
gCurrentTabID = gParamArray[0]; // tabID of FF visible Tab
gNodeListLoadLen = gNodeList.length; // Used in onFocus()
// Initialize other key globals
gTabRoots = new Array();
gTreeNodes = new Array();
gSearchIndexes = new Array();
gSearchNdx = -1;
gTreeMinY = 0;
gSubTreeSize = 0;
gCurrentView = TREE_VIEW;
gExpandedNode = null;
gImgXY = new Point(0, 0);
gInfoBoxWH = new Point(0, 0);
gNodeImageWid = 0;
// ---------------------------------------------------
// Show history view or a "No history" info message
if (gNodeList.length > 0)
{
// Show history view using GUI options saved in App storage
showLoadedHistoryView();
}
else
{
// Show a message if no pages in window history *** BUT NOTE
// gTreeNodes[] and other key globals are NOT set in this case
showBigMessageOnEmptyCanvas
("No pages in window history", "bold 14pt verdana");
}
// Set reload completion global flag (** DO NOT do this earlier)
gTabLoadInterval = null;
}
// ==================================================================
// Shows FF window history using user's GUI options from App Storage
// ==================================================================
function showLoadedHistoryView()
{
// Init all vars
var btnTreeView = document.getElementById("btnTreeView");
var btnGridView = document.getElementById("btnGridView");
var lblSliderHdr = document.getElementById("lblSliderHdr");
var sldDraw = document.getElementById("sldDraw");
var optGrpView = document.getElementById("optGrpView");
var chkSearchURL = document.getElementById("chkSearchURL");
var listSelTab = document.getElementById("listSelTab");
var viewNum;
var radioOpt;
var borderSize;
// ------------------------------------------------------------------
// Create gTreeNodes[] & gTabRoots[] using retrieved App storage data
buildFullHistoryTree();
// Create gSearchIndexes[] - Enabling consistant search order
createGlobalSearchIndexesArray();
// Fill "historyViewer.xul" <listbox...> with Tab root page descs
// This also sets <listbox...> selected item = gCurrentTabID FF Tab
fillListboxWithTabRootDescriptions();
// Re-enable "historyViewer.xul" top-panel GUI controls
disableOrEnableGUIcontrols(false);
listSelTab.focus(); // <listbox...>
// -----------------------------------------------------------
// Setup "historyViewer.xul" GUI for GV or TV (default is TV)
gCurrentView = Application.storage.get("GVorTVbuttonVal", TREE_VIEW);
if (gCurrentView === GRID_VIEW)
{
// Set GUI controls for GridView
btnGridView.src = "images/btnGVin.gif";
btnTreeView.src = "images/btnTVout.gif";
sldDraw.value = Application.storage.get("gridViewSliderVal", 4);
lblSliderHdr.value = "Image Size";
}
else
{
// Set GUI controls for TreeView
btnTreeView.src = "images/btnTVin.gif";
btnGridView.src = "images/btnGVout.gif";
sldDraw.value = Application.storage.get("treeViewSliderVal", 1);
lblSliderHdr.value = "Tree Spacing";
// Reset tree-spacing using slider value
borderSize = (sldDraw.value * BORDER_STEP) + NODE_BORDER;
setBorderForAllNodes(borderSize);
}
// -----------------------------------------------------------
// Show user's chosen quick-view (default is "Show open tabs")
if (numExtWinOpenTabs() > 0)
{
// Get user's quick-view choice from App Storage
viewNum = Application.storage.get("quickViewOptGrpVal", 0);
}
else
{
// No open Tabs - So disable open Tabs quick-view options
radioOpt = document.getElementById("optOpenTabs");
radioOpt.disabled = true;
radioOpt = document.getElementById("optOpenPages");
radioOpt.disabled = true;
viewNum = 3; // "Show closed tabs"
}
// Set <radiogroup...> option for quick-view, then show that quick-view
optGrpView.selectedIndex = viewNum;
showQuickView(viewNum);
// Set search <textbox...> backColor - Found = "white", Not found = "red"
chkSearchURL.checked = Application.storage.get("searchCheckboxVal", true);
setSearchTextBoxColor(chkSearchURL.checked);
}
// ==================================================================
// Fills "historyViewer.xul" <listbox...> with Tab root page descs
// ==================================================================
function fillListboxWithTabRootDescriptions()
{
// Init vars
var listSelTab = document.getElementById("listSelTab");
var listItemTxt;
var tabRoot;
var startNdx = 0;
var listItem;
var itemTxtCol;
// -------------------------------------------
// Remove all items from the <listbox...>
while (listSelTab.itemCount > 0)
listSelTab.removeItemAt(0);
// Fill the <listbox...> with Tab root descriptions
for (var i = 0; i < gTabRoots.length; i++)
{
// Get Tab root TreeNode object
tabRoot = gTabRoots[i];
// Set <listbox...> item number prefix
listItemTxt = (i + 1).toString() + " - ";
// Add web-page description from Tab root HistoryNode
listItemTxt += tabRoot.histNode.desc;
// Add item to <listbox...> including tabID as item.value
listSelTab.appendItem(listItemTxt, tabRoot.histNode.tab);
// Set listitem font color
if (tabRoot.histNode.tab === gCurrentTabID)
itemTxtCol = "rgb(255,80,0)"; // Orange
else if (!tabRoot.inOpenTab)
itemTxtCol = "rgb(61,110,255)"; // Blue
else
itemTxtCol = "black";
listItem = listSelTab.getItemAtIndex(i);
listItem.style.color = itemTxtCol;
// Set <listbox...>.selectedIndex (see *** NOTE below)
if (tabRoot.histNode.tab === gCurrentTabID)
startNdx = i;
}
// ---------------------------------------------------------------
// Show selected <listbox...> item. This seems like a kludge, but
// <listbox...> needs time to populate before item can be selected
listSelTab.ensureIndexIsVisible(startNdx);
listSelTab.selectedIndex = startNdx;
gTimeoutInterval = setTimeout
(setListboxSelectedItem, listSelTab.itemCount * 15, startNdx);
}
// ============================================================
// Sets <listbox...> selected item after calculated time delay
// ============================================================
function setListboxSelectedItem(startNdx)
{
// Stop setTimeout() and set global flag
clearTimeout(gTimeoutInterval);
gTimeoutInterval = null;
// Highlight selected <listbox...> item
var listSelTab = document.getElementById("listSelTab");
listSelTab.ensureIndexIsVisible(startNdx);
listSelTab.selectedIndex = startNdx;
}
// ==========================================================
// Updates "historyViewer.xul" <listbox...> listItem labels
// ==========================================================
function updateListboxTabRootDescriptions()
{
// Init vars
var listSelTab = document.getElementById("listSelTab");
var tabRoot;
var listItem;
var listItemTxt;
var itemTxtCol;
// --------------------------------------------------
// Update <listbox...> Tab root descriptions
for (var i = 0; i < gTabRoots.length; i++)
{
// Make sure <listbox...> item exists
if (listSelTab.itemCount > i)
{
// Set listItem label prefix
tabRoot = gTabRoots[i];
listItemTxt = (i + 1).toString() + " - ";
// Update listItem.label
listItem = listSelTab.getItemAtIndex(i);
listItem.label = listItemTxt + tabRoot.histNode.desc;
// Update listitem font color
if (tabRoot.histNode.tab === gCurrentTabID)
itemTxtCol = "rgb(255,80,0)"; // Orange
else if (!tabRoot.inOpenTab)
itemTxtCol = "rgb(61,110,255)"; // Blue
else
itemTxtCol = "black";
// Set listitem font color
listItem.style.color = itemTxtCol;
}
}
}
// ****************************************************************
// ***** *****
// ***** EVENT HANDLING PROCEDURES *****
// ***** USED BY BOTH TREE-VIEW AND GRID-VIEW *****
// ***** *****
// ****************************************************************
// =================================================================
// Returns true if invalid setInterval() or setTimeout() is running
// Prevents use of this window's GUI controls during timed proceses
// =================================================================
function setIntervalOrTimeoutRunning()
{
if (gTabLoadInterval !== null || gImgExpandInterval !== null
|| gTimeoutInterval !== null)
{
// This window's setInterval() or setTimeout() is running
return true;
}
else
{
// No window timed events are occuring
return false;
}
}
// ================================================================
// Called from TWO "historyViewer.xul" <image...> onclick() events
// ================================================================
function reloadButtonEventHandler(event)
{
// Exit if a setInterval() or setTimeout() is running
if (setIntervalOrTimeoutRunning() || gGVdispInterval !== null)
return;
// Init vars
var btnNextWin, btnPrevWin;
if (event.target.id == "btnNextWin")
{
// Show Next FF win button briefly pushed in
btnNextWin = document.getElementById("btnNextWin");
btnNextWin.src = "images/btnNextWinIn.gif";
// Load history for Next FF window
gTimeoutInterval = setTimeout
(loadHistoryForNextOrPrevFFwindow, 100, true);
}
else
{
// Show Previous FF win button briefly pushed in
btnPrevWin = document.getElementById("btnPrevWin");
btnPrevWin.src = "images/btnPrevWinIn.gif";
// Load history for Previous FF window
gTimeoutInterval = setTimeout
(loadHistoryForNextOrPrevFFwindow, 100, false);
}
}
// ========================================================
// Called via setTimeout() from reloadButtonEventHandler()
// ========================================================
function loadHistoryForNextOrPrevFFwindow(nextWin)
{
// Init vars
var btnNextWin, btnPrevWin;
// Stop setTimeout() and set global flag
clearTimeout(gTimeoutInterval);
gTimeoutInterval = null;
// Show Next/Previous FF win button pushed out
if (nextWin)
{
btnNextWin = document.getElementById("btnNextWin");
btnNextWin.src = "images/btnNextWinOut.gif";
}
else
{
btnPrevWin = document.getElementById("btnPrevWin");
btnPrevWin.src = "images/btnPrevWinOut.gif";
}
// Set this windows opener as Next/Prev open FF window
gParentFFWin = nextOrPrevFFwindow(nextWin);
gParentFFWin.historyTree.cExtHistTreeWin = this;
// Rebuild key global vars and re-display GV or TV
updateHistoryWhenAllTabsLoaded();
}
// ===============================================================
// Called from TWO "historyViewer.xul <image...> onclick() events
// ===============================================================
function searchButtonEventHandler(event)
{
// Exit if a setInterval() or setTimeout() is running
if (setIntervalOrTimeoutRunning() || gGVdispInterval !== null
|| gNodeList.length === 0)
return;
// ------------------------------------------------------
// Init vars
var txtFind, chkSearchURL;
var btnFindNext, btnFindPrev;
var txtToFind;
var searchURL;
txtFind = document.getElementById("txtFind");
txtToFind = (txtFind.value).toUpperCase();
chkSearchURL = document.getElementById("chkSearchURL");
searchURL = chkSearchURL.checked;
// Perform search if <textbox...> text is found
if (txtToFind !== "" && searchTextFound(txtToFind, searchURL))
{
if (event.target.id === "btnFindNext")
{
// Find Next page with matching <textbox...> text
btnFindNext = document.getElementById("btnFindNext");
btnFindNext.src = "images/btnNextIn.gif";
gTimeoutInterval = setTimeout
(searchTree, 100, true, txtToFind, searchURL);
}
else
{
// Find Prev page with matching <textbox...> text
btnFindPrev = document.getElementById("btnFindPrev");
btnFindPrev.src = "images/btnPrevIn.gif";
gTimeoutInterval = setTimeout
(searchTree, 100, false, txtToFind, searchURL);
}
}
}
// ============================================================
// Called from "historyViewer.xul" <textbox ...> onkeyup event
// ============================================================
function searchTextboxEventHandler(event)
{
// Make <textbox...> background red if text is not found
var chkSearchURL = document.getElementById("chkSearchURL");
if (!chkSearchURL.disabled)
setSearchTextBoxColor(chkSearchURL.checked);
}
// =============================================================
// Called from "historyViewer.xul" <checkbox ...> onclick event
// =============================================================
function searchCheckboxEventHandler(event)
{
// Do nothing if <checkbox...> is disabled
if (!event.target.disabled)
{
// Make <textbox...> background red if text is not found
var checked = !event.target.checked;
Application.storage.set("searchCheckboxVal", checked);
setSearchTextBoxColor(checked);
}
}
// ===============================================================
// Called from TWO "historyViewer.xul <image...> onclick() events
// ===============================================================
function imageButtonClickEventHandler(event)
{
// Exit if a setInterval() or setTimeout() is running
if (setIntervalOrTimeoutRunning() || gNodeList.length === 0)
return;
// Get "historyViewer.xul" controls and init vars
var btnGridView = document.getElementById("btnGridView");
var btnTreeView = document.getElementById("btnTreeView");
var sldDraw = document.getElementById("sldDraw");
var lblSliderHdr = document.getElementById("lblSliderHdr");
var optGrpView = document.getElementById("optGrpView");
var borderSize = 0;
// --------------------------------------------
if (event.target.id === "btnGridView"
&& btnGridView.src === "images/btnGVout.gif")
// --------------------------------------------
{
// Change to GridView and save it to App Storage
gCurrentView = GRID_VIEW;
Application.storage.set("GVorTVbuttonVal", GRID_VIEW);
// Change GUI controls for GridView
btnGridView.src = "images/btnGVin.gif";
btnTreeView.src = "images/btnTVout.gif";
// Set <scale...> (slider) attributes
sldDraw.value = Application.storage.get("gridViewSliderVal", 4);
lblSliderHdr.value = "Image Size";
// Draw all ".jpeg" images on the gCanvas
var numAcross = (sldDraw.max - sldDraw.value) + 3;
drawAllImagesOnCanvas(numAcross, true);
}
// --------------------------------------------
if (event.target.id === "btnTreeView"
&& btnTreeView.src === "images/btnTVout.gif")
// --------------------------------------------
{
// Change to TreeView and save it to App Storage
gCurrentView = TREE_VIEW;
Application.storage.set("GVorTVbuttonVal", TREE_VIEW);
// Change GUI controls for TreeView
btnTreeView.src = "images/btnTVin.gif";
btnGridView.src = "images/btnGVout.gif";
// Set <scale...> (slider) attributes
sldDraw.value = Application.storage.get("treeViewSliderVal", 1);
lblSliderHdr.value = "Tree Spacing";
// Reset tree-spacing using slider value
borderSize = (sldDraw.value * BORDER_STEP) + NODE_BORDER;
setBorderForAllNodes(borderSize);
// Draw tree, scrolling as required
if (optGrpView.selectedIndex === 0)
// "Show open tabs"
drawTree(false, gCurrentTabID, null);
else
// Other quick-views
drawTree(true, null, null);
}
}
// ====================================================================
// Called from "historyViewer.xul <scale...> onmouseup() and onkeyup()
// ====================================================================
function sliderChangeEventHandler(event)
{
// Exit if a setInterval() or setTimeout() is running
if (setIntervalOrTimeoutRunning() || gNodeList.length === 0)
return;
// Clear the gCanvas
gCtx.fillStyle = CANVAS_BAK_COL; // Dark grey
gCtx.fillRect(0, 0, gCanvas.width, gCanvas.height);
// Draw all nodes on gCanvas depending on current view
var sliderVal = event.target.value;
if (gCurrentView === GRID_VIEW)
{
// Draw all images on the gCanvas
Application.storage.set("gridViewSliderVal", sliderVal);
var numAcross = (event.target.max - sliderVal) + 3;
drawAllImagesOnCanvas(numAcross, true);
}
else
{
// Reset tree-spacing then redraw tree
Application.storage.set("treeViewSliderVal", sliderVal);
var borderSize = (sliderVal * BORDER_STEP) + NODE_BORDER;
setBorderForAllNodes(borderSize);
drawTree(false, null, null);
}
}
// =========================================================
// Called from "historyViewer.xul" <listbox ...> onclick()
// Redraws FULL Tab sub-tree (collapsed sub-trees reappear)
// =========================================================
function listboxClickEventHandler(event)
{
// Exit if a setInterval() or setTimeout() is running
if (setIntervalOrTimeoutRunning() || gNodeList.length === 0)
return;
// Set <radiogroup ...> option for "Show selected tab" quick-view
var optGrpView = document.getElementById("optGrpView");
optGrpView.selectedIndex = 2;
Application.storage.set("quickViewOptGrpVal", 2);
// Show the "Show selected tab" quick-view
showQuickView(2);
}
// =================================================================
// Shows selected quick-view - Called from FOUR "historyViewer.xul"
// <radio...> onclick() events and from <radiogroup...> onkeyup()
// =================================================================
function quickViewOptEventHandler(optNum)
{
// Exit if a setInterval() or setTimeout() is running
if (setIntervalOrTimeoutRunning() || gNodeList.length === 0)
return;
// Get optNum from <radiogroup...> if its onkeyup() fired
var optGrpView = document.getElementById("optGrpView");
if (optNum === -1)
optNum = optGrpView.selectedIndex;
// Show GV or TV quick-view for selected option
optGrpView.selectedIndex = optNum; // Needed
Application.storage.set("quickViewOptGrpVal", optNum);
showQuickView(optNum);
}
// ==============================================================
// Shows GV or TV quick-view for passed <radiogroup...> optNum
// ==============================================================
function showQuickView(optNum)
{
// Set TreeNode pointers for passed quick-view optNum
setTreeNodePointersForSelectedQuickView(optNum);
// Draw the required GV or TV quick-view on gCanvas
if (gCurrentView === TREE_VIEW)
{
if (optNum === 0)
// TV "Show open tabs"
drawTree(false, gCurrentTabID, null);
else
// TV Other quick-views
drawTree(true, null, null);
}
else
{
// Draw GV quick-view using req number of images per row
var sldDraw = document.getElementById("sldDraw");
var numAcross = (sldDraw.max - sldDraw.value) + 3;
drawAllImagesOnCanvas(numAcross, true);
}
}
// ==============================================================
// Sets TreeNode pointers for passed optNum - BUT does not draw
// ==============================================================
function setTreeNodePointersForSelectedQuickView(optNum)
{
// Init vars
var listSelTab; // <listbox...>
var selItem; // <listbox...> item
// -----------------------------------------------------
// Set TreeNode pointers for passed quick-view optNum
if (optNum === 0)
{
// "Show open tabs"
setTreePointersFor_OpenTabsQuickView();
}
else if (optNum === 1)
{
// "Show open pages"
setTreePointersFor_OpenPagesQuickView();
}
else if (optNum === 2)
{
// "Show selected tab" using <listbox...> item tabID
listSelTab = document.getElementById("listSelTab");
selItem = listSelTab.getSelectedItem(0);
setTreePointersFor_SelectedTabQuickView(selItem.value);
}
else if (optNum === 3)
{
// "Show closed tabs"
setTreePointersFor_ClosedTabsQuickView();
}
}
// ===============================================================
// Called when user clicks mouse on gCanvas in either GV or TV
// ===============================================================
function canvasMouseClickEventHandler(event)
{
// Exit if a setInterval() or setTimeout() is running
if (setIntervalOrTimeoutRunning() || gGVdispInterval !== null
|| gNodeList.length === 0)
return;
// Get current <scrollbox...> scrollbars (x, y) positions
var xs = {}; // object
var ys = {}; // object
gCanvasScroller.getPosition(xs, ys);
// Get mouse click (x, y) adjusting for scrollbars (x, y)
// where (0, 0) is top-left corner of window NOT gCanvas
mouseX = event.clientX + xs.value;
mouseY = event.clientY + ys.value - gCanvas.offsetTop;
// ----------------------------------------------------
// Do required action depending on the current view
if (gCurrentView === GRID_VIEW)
{
// Get TreeNode for GV image user clicked on (if any)
var tNode = gridViewTreeNodeFromMouseXY(mouseX, mouseY);
// Open page in FF if user clicked on GV ".jpeg" image
if (tNode !== null)
openOrGotoSelectedHistoryPage(tNode);
}
else // TREE_VIEW
{
// Call "treeViewChanger.js" TV mouse-click handler
respondToTreeViewMouseClickOnCanvas(mouseX, mouseY);
}
}
// ****************************************************
// ***** *****
// ***** UTILITY FUNCTIONS *****
// ***** USED BY "historyViewer.xul" JS FILES *****
// ***** *****
// ****************************************************
// =========================================================
// Called from "historyViewer.js" or "treeViewChanger.js"
// when user clicks on a gCanvas TV TreeNode or GV ".jpeg"
// =========================================================
function openOrGotoSelectedHistoryPage(tNode)
{
// Show goto/open page modal Dialog window
if (tNode !== null)
{
// Put App Storage data used by the window opened below
Application.storage.set("openPageTreeNode", tNode);
// Define a resizable dialog window with no max/min/close buttons and
// no right-click context menu, which will open modally at center screen
var chromeFeatures = "chrome,centerscreen,modal=yes,resizable=yes,close=no";
var winPath = "chrome://historyTree/content/openPageDialog.xul";
window.openDialog(winPath,"pageOpener",chromeFeatures);
}
}
// =============================================================
// ONLY called from modal window "openPageDialog.js" onUnload()
// =============================================================
function showHistoryPageInFirefox(optNum, selTabID)
{
// Check if user is opening a new page in FF
if (optNum !== 0)
{
// Set global flags that will force full data update/refresh when
// this window's onFocus() event fires (focus is changed below)
gExitWinFocusEvent = false;
gNodeListLoadLen = null;
}
// Set focus to current parent FF window (MUST be done first)
gParentFFWin.focus();
// Call "firefoxOverlay.js" method to open/goto history page
var tNode = Application.storage.get("openPageTreeNode", null);
if (tNode !== null)
gParentFFWin.historyTree.openOrGotoHistoryPage(tNode, optNum, selTabID);
}
// ============================================================
// Returns Next/Previous open FF window using cyclic retrieval
// ============================================================
function nextOrPrevFFwindow(nextWin)
{
var wm; // nsIWindowMediator
var enum; // Simple nsI enumerator
var win, reqWin; // Open FF windows
var winList = new Array(); // List of open FF windows
var currWinNum; // Integer
// ---------------------------------------------------
// Create array list of all open FF windows
wm = Components.classes["@mozilla.org/appshell/window-mediator;1"]
.getService(Components.interfaces.nsIWindowMediator);
enum = wm.getEnumerator("navigator:browser");
while (enum.hasMoreElements())
{
win = enum.getNext();
winList.push(win);
if (win === gParentFFWin)
currWinNum = winList.length - 1;
}
// ---------------------------------------------------
// Get Next/Prev open FF window using cyclic retrieval
if (nextWin)
{
if (currWinNum === winList.length - 1)
reqWin = winList[0];
else
reqWin = winList[currWinNum + 1];
}
else
{
if (currWinNum === 0)
reqWin = winList[winList.length - 1];
else
reqWin = winList[currWinNum - 1];
}
// Clear temp array then return Next/Prev FF win
winList.splice(0);
return reqWin;
}
// ===================================================================
// Set "Window x of y" label text - Called via onLoad() and onFocus()
// ===================================================================
function setLabelText_WindowXofY()
{
var wm; // nsIWindowMediator
var enum; // Simple nsI enumerator
var win; // Open FF window
var currWinNum, numWin; // Integers
// ------------------------------------------------
// Get list of all open FF windows
wm = Components.classes["@mozilla.org/appshell/window-mediator;1"]
.getService(Components.interfaces.nsIWindowMediator);
enum = wm.getEnumerator("navigator:browser");
// Get numbers used for label
numWin = 0;
while (enum.hasMoreElements())
{
numWin ++;
win = enum.getNext();
if (win === gParentFFWin)
currWinNum = numWin;
}
// Set "Window x of y" label text
var lblWinInfo = document.getElementById("lblWinInfo");
lblWinInfo.value = "Window " + currWinNum.toString()
+ " of " + numWin.toString();
}
// =================================================================
// Disables or enables GUI controls while setInterval() running etc
// =================================================================
function disableOrEnableGUIcontrols(disable)
{
// Don't re-enable if no FF history
if (!disable && gNodeList.length === 0)
return;
// Get references to "historyViewer.xul" GUI controls
var optGrpView = document.getElementById("optGrpView");
var listSelTab = document.getElementById("listSelTab");
var txtFind = document.getElementById("txtFind");
var chkSearchURL = document.getElementById("chkSearchURL");
var sldDraw = document.getElementById("sldDraw");
// Remove items from <listbox...> if disabling
if (disable)
{
while (listSelTab.itemCount > 0)
listSelTab.removeItemAt(0);
}
// Set search <textbox...> backcolor
if (disable)
txtFind.style.backgroundColor = "#cccccc"; // Grey
else
txtFind.style.backgroundColor = "#ffffff"; // White
// Disable or enable other GUI controls
optGrpView.disabled = disable;
listSelTab.disabled = disable;
chkSearchURL.disabled = disable;
sldDraw.disabled = disable;
}
// ==============================================================
// Loads node ".jpeg" from its dataURL, then draws it on gCanvas
// This is only done ONCE for each node (to speed up redraws)
// ==============================================================
function drawAndUpdateNodeImage(node, x, y, w, h)
{
// Try to draw the node's ".jpeg" image on the gCanvas
try
{
// Create node ".jpeg", then draw it on gCanvas *** NOTE
// Many tests showed this to be the most reliable approach
node = nodeWithImage(node);
gCtx.drawImage(node.imgToDraw, x, y, w, h);
}
catch (e)
{
// Nothing will be drawn on gCanvas
node.imgData = null;
}
}
// =====================================================
// Returns passed hNode with its ".jpeg" image loaded
// =====================================================
function nodeWithImage(hNode)
{
var img = new Image();
// Wait until the image loads
img.onload = function()
{
// Return node with image props set
hNode.imgToDraw = img;
hNode.imgCreated = true;
return hNode;
};
// This MUST be done here or sometimes onload() is NOT called
img.src = hNode.imgData;
}
// ==============================================================
// Returns true if a blank rectangle is drawn instead of ".jpeg"
// ==============================================================
function blankRectangleDrawn(hNode, x, y, w, h, roundRect, bordCol)
{
// Init integers
var suffixPos;
var fontSize;
var reqWid, txtWid;
var textX, textY, yAddOn;
var rectMsg; // String
// -------------------------------------------
// Check if a blank rectangle should be drawn
suffixPos = hNode.uri.length - 4;
if (hNode.imgData === null
|| hNode.uri.lastIndexOf(".pdf") === suffixPos)
{
rectMsg = "Image not available";
}
else
{
return false;
}
// -------------------------------------------
// Draw a white rectangle with border
if (roundRect)
{
// Rounded corner rect with highlighted border
gCtx.lineWidth = 3;
drawRoundedRectWithBorder
(x - 2, y - 2, w + 4, h + 4, 10, "white", bordCol);
}
else
{
// Square rectangle with black border
drawBorderedRect
(x - 1, y - 1, w + 2, h + 2, "white", bordCol, 2);
}
// ---------------------------------------------
// Init while() loop font/text sizing vars
reqWid = Math.round(w * 0.6);
fontSize = 7;
gCtx.mozTextStyle = "bold " + fontSize.toString() + "pt verdana";
txtWid = gCtx.mozMeasureText(rectMsg);
// Keep increasing font size until rectMsg reaches reqWid
while (txtWid < reqWid && fontSize < 14)
{
fontSize ++;
gCtx.mozTextStyle = "bold " + fontSize.toString() + "pt verdana";
txtWid = gCtx.mozMeasureText(rectMsg);
}
// Draw sized rectMsg text inside the rectangle
textX = Math.round(x + (w - txtWid) / 2);
textY = Math.round(y + (h / 2));
yAddOn = Math.ceil((14 - fontSize) / 2);
gCtx.fillStyle = "rgb(190,190,190)"; // Light grey
fillText(rectMsg, textX, textY + yAddOn);
// -------------------------------------------
// White rectangle WAS drawn
return true;
}
// ============================================================
// Returns number of open Tab header TreeNode's in gTabRoots[]
// ------------------------------------------------------------
// *** NOTE - Blank FF Tabs are not shown AT ALL in GV or TV
// ============================================================
function numExtWinOpenTabs()
{
// Get count of open Tab TreeNode's in gTabRoots[]
var tabRoot;
var numOpen = 0;
for (var ndx = 0; ndx < gTabRoots.length; ndx++)
{
tabRoot = gTabRoots[ndx];
if (tabRoot.inOpenTab)
numOpen ++;
}
// Return the count
return numOpen;
}
// ================================================================
// Use Mozilla method to draw text on the gCanvas
// *** NOTE - This allows easy find/replace changeover for FF 3.5
// mozTextStyle can also be globally replced with font()
// ================================================================
function fillText(text, x, y)
{
gCtx.translate(x, y);
gCtx.mozDrawText(text);
gCtx.translate((-1 * x), (-1 * y));
//gCtx.fillRect(1,1,1,1);
}
// ======================================================
// Clears gCanvas, then shows passed msg in passed font
// ======================================================
function showBigMessageOnEmptyCanvas(msg, font)
{
// Init vars
var textX; // Integer
var xs = {}; // object
var ys = {}; // object
// --------------------------------------------
// Clear the gCanvas
gCtx.fillStyle = CANVAS_BAK_COL; // Dark grey
gCtx.fillRect(0, 0, gCanvas.width, gCanvas.height);
// Calculate x co-ordinate for drawing passed msg
gCtx.mozTextStyle = font;
textX = Math.round((this.innerWidth - gCtx.mozMeasureText(msg)) / 2);
if (textX < 0)
textX = 0;
// Show "Loading..." message centre screen
gCanvasScroller.getPosition(xs, ys);
gCtx.fillStyle = "white";
fillText(msg, xs.value + textX, ys.value + 85);
}
// =======================================================
// Returns a "trimmed" version of the passed string
// =======================================================
function trim(s)
{
s = s.replace( /^\s*/, ""); // Trims leading spaces
s = s.replace( /\s*$/, ""); // Trims trailing spaces
return s;
}
// =======================================================
// Returns a "truncated" version of passed string
// =======================================================
function truncatedText(text, reqWidth)
{
text = trim(text); // Trim passed text
var truncText = text;
var len = text.length;
// Keep chopping chars off end of text until its short enough
while(gCtx.mozMeasureText(truncText) > reqWidth && truncText.length > 0)
{
len--;
truncText = text.substring(0, len);
}
// Return truncated string or original if not truncated
truncText = trim(truncText);
if (truncText.length < text.length)
return truncText.substring(0, len - 1) + "...";
else
return text;
}
// =========================================================
// ****** TEST FUNCTION ******
// Returns a string describing properties of passed obj
// =========================================================
function showPropertiesOf(obj)
{
var rowTot = 0;
var propList = "";
for (var prop in obj)
{
propList += prop + " = " + obj[prop] + "....";
rowTot ++;
if (rowTot > 4)
{
rowTot = 0;
propList += "\n";
}
}
return propList;
}